﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using static cs.IntropCppTest;

namespace cs
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            IntropCppTest.Int_Test();
            IntropCppTest.String_Test();
            IntropCppTest.Class_Test();
            IntropCppTest.Struct_Test();
            Console.WriteLine("测试完成");

            IntrophdCodeTest.RunTest();

            Console.ReadLine();
        }
    }

    public static class IntropCppTest
    {
        public static void Int_Test()
        {
            Console.WriteLine();
            int a = 111, b = 222;
            int c = IntropCpp.Add(a, b);
            Debug.Assert(c == (a + b));

            int[] ra = new int[] { 5, 4, 3, 2, 1 };
            int sum = IntropCpp.Sum(ra);
            Debug.Assert(sum == ra.ToList().Sum());

            int[] range;
            IntropCpp.Range(1, 5, out range);
            for (int i = 0; i < range.Length; i++)
            {
                Debug.Assert(range[i] == i + 1);
            }

            int[] sortInput = new int[] { 6, 5, 4, 3, 2, 1 };
            int[] sortOutput;
            IntropCpp.Sort(sortInput, out sortOutput);
            Array.Sort(sortInput);
            for (int i = 0; i < sortInput.Length; i++)
            {
                Debug.Assert(sortInput[i] == sortOutput[i]);
            }
            Console.WriteLine("C#--->C/Cpp 整型测试通过");
        }

        public static void String_Test()
        {
            Console.WriteLine();
            //var str = IntropCpp.GetCallReason();
            //Console.WriteLine("Call　Reason：" + str);
            var uwstr = "你好ABCxyz123！@#￥";
            var upstr = "";
            var lostr = "";
            IntropCpp.UpperLower(uwstr, out upstr, out lostr);
            Console.WriteLine("Input：" + uwstr);
            Console.WriteLine("Upper：" + upstr);
            Console.WriteLine("Lower：" + lostr);
            var pstr = "123ABCxyz!@#中文符号。￥xyz";
            IntropCpp.OutputString();

            IntropCpp.Printf(pstr);
            Console.WriteLine("C#--->C/Cpp 字符串测试通过");
        }

        public static void Class_Test()
        {
            Console.WriteLine();
            //必须使用非托管指针，不能使用IntPtr.Zero,以及new IntPtr()
            IntPtr ptr1 = Marshal.AllocHGlobal(IntPtr.Size);
            IntPtr ptr2 = Marshal.AllocHGlobal(IntPtr.Size);
            float x1 = 1, y1 = 1, x2 = 4, y2 = 4;

            int r1 = IntropCpp.CreatePoint(ptr1, x1, y1);
            float rg1 = IntropCpp.Distance(ptr1);

            int r2 = IntropCpp.CreatePoint(ptr2, x2, y2);
            float rg2 = IntropCpp.Distance(ptr2);

            float rg12 = IntropCpp.Distance2(ptr1, ptr2);
            float rg21 = IntropCpp.Distance2(ptr2, ptr1);

            var arg1 = (float)Math.Sqrt(Math.Pow(x1, 2) + Math.Pow(y1, 2));
            var arg2 = (float)Math.Sqrt(Math.Pow(x2, 2) + Math.Pow(y2, 2));
            var arg12 = (float)Math.Sqrt(Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2));

            //IntropCpp.DeletePoint(ptr1);
            //IntropCpp.DeletePoint2(ptr2);

            Debug.Assert(rg1.Equal(arg1));
            Debug.Assert(rg2.Equal(arg2));
            Debug.Assert(rg2.Equal(arg2));
            Debug.Assert(rg12.Equal(arg12));
            Debug.Assert(rg12.Equal(rg21));

            Console.WriteLine("C#--->C/Cpp 类测试通过");
        }

        public struct IpInfo
        {
            public int IP;
            public int Mask;
            public static int Parse(string ip)
            {
                var ss = ip.Split('.');
                var v0 = byte.Parse(ss[0]);
                var v1 = byte.Parse(ss[1]);
                var v2 = byte.Parse(ss[2]);
                var v3 = byte.Parse(ss[3]);
                return (v0 << 24) | (v1 << 16) | (v2 << 8) | (v3 << 0);
            }
        };

        public struct Name
        {
            public static Name Empty
            {
                get
                {
                    return new Name()
                    {
                        V0 = '\0'
                    };
                }
            }
            public char V0;
            public char V1;
            public char V2;
            public char V3;
            public char V4;
            public static implicit operator Name(string str)
            {
                if (string.IsNullOrEmpty(str))
                    return Name.Empty;
                if (str.Length >= 4)
                    return new Name()
                    {
                        V4 = '\0',
                        V0 = str[0],
                        V1 = str[1],
                        V2 = str[2],
                        V3 = str[3],
                    };
                else
                    return new Name()
                    {
                        V4 = '\0',
                        V0 = str[0],
                        V1 = '$',
                        V2 = '#',
                        V3 = '$',
                    };
            }
        }

        public struct Host
        {
            public IpInfo ip;
            public Name name;
        }

        public static void Struct_Test()
        {
            Console.WriteLine("C#--->C/Cpp 结果体测试");
            var ip = new IpInfo()
            {
                IP = IpInfo.Parse("192.168.0.168"),
                Mask = IpInfo.Parse("255.255.0.0"),
            };
            var size = Marshal.SizeOf(ip);
            var ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(ip, ptr, true);
            IntropCpp.Input(0, ptr, 1);
            Marshal.DestroyStructure(ptr, typeof(IpInfo));
            IntropCpp.InputEx(0, ip, 1);

            var host = new Host()
            {
                ip = ip,
                name = "w550",
            };

            IntropCpp.InputEx(1, host, 1);

            Console.WriteLine("C#--->C/Cpp 结果体测试完成");
        }

        public static bool Equal(this float a, float b, float d = 1E-5f)
        {
            return Math.Abs(a - b) < d;
        }
    }

    public static class IntropCpp
    {
        private const string _cppDll = "cpp.dll";

        #region 整型与指针

        /// <summary>
        /// 输出为返回值
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        [DllImport(_cppDll)]
        private static extern int Add0(int a, int b);

        /// <summary>
        /// 输出为整型指针，对于输出整型指针使用ref int
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        [DllImport(_cppDll)]
        private static extern void Add1(int a, int b, ref int c);

        /// <summary>
        /// 输出为整型指针，对于输出整型指针使用 IntPtr
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        [DllImport(_cppDll)]
        private static extern void Add1(int a, int b, IntPtr c);

        /// <summary>
        /// 输入输出都是整型指针，使用ref int
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        [DllImport(_cppDll)]
        private static extern void Add2(ref int a, ref int b, ref int c);

        /// <summary>
        /// 输入输出都是整型指针，使用 IntPtr
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        [DllImport(_cppDll)]
        private static extern void Add2(IntPtr a, IntPtr b, IntPtr c);

        [DllImport(_cppDll)]
        private static extern void Add3(IntPtr a, IntPtr b, IntPtr c);

        public static int Add(int a, int b)
        {
            int c = IntropCpp.Add0(a, b);
            Debug.Assert(c == (a + b), "Add0");

            c = 0;
            IntropCpp.Add1(a, b, ref c);
            Debug.Assert(c == (a + b), "Add1 ref");

            c = 0;
            IntPtr pc = Marshal.AllocCoTaskMem(sizeof(int) * 1);
            IntropCpp.Add1(a, b, pc);
            c = Marshal.ReadInt32(pc);
            Marshal.FreeCoTaskMem(pc);
            Debug.Assert(c == (a + b), "Add1 IntPtr");

            c = 0;
            IntPtr pc2 = Marshal.AllocHGlobal(sizeof(int) * 1);
            IntropCpp.Add1(a, b, pc2);
            c = Marshal.ReadInt32(pc2);
            Marshal.FreeHGlobal(pc2);
            Debug.Assert(c == (a + b), "Add1 IntPtr");

            c = 0;
            IntropCpp.Add2(ref a, ref b, ref c);
            Debug.Assert(c == (a + b), "Add2 Ref");

            c = 0;
            //构建指针，申请内存空间
            IntPtr pa2 = Marshal.AllocCoTaskMem(sizeof(int) * 1);
            IntPtr pb2 = Marshal.AllocCoTaskMem(sizeof(int) * 1);
            IntPtr pc22 = Marshal.AllocCoTaskMem(sizeof(int) * 1);
            IntPtr pc23 = Marshal.AllocCoTaskMem(sizeof(int) * 1);
            //指针地址传递数据
            Marshal.Copy(new int[1] { a }, 0, pa2, 1);
            Marshal.Copy(new int[1] { b }, 0, pb2, 1);
            Marshal.Copy(new int[1] { 0 }, 0, pc22, 1);
            Marshal.Copy(new int[1] { 0 }, 0, pc23, 1);
            IntropCpp.Add2(pa2, pb2, pc22);
            IntropCpp.Add3(pa2, pb2, pc23);

            var c1 = Marshal.ReadInt32(pc22, 0);
            var c2 = Marshal.ReadInt32(pc23, 0);
            Marshal.FreeCoTaskMem(pa2);
            Marshal.FreeCoTaskMem(pb2);
            Marshal.FreeCoTaskMem(pc22);
            Marshal.FreeCoTaskMem(pc23);
            Debug.Assert(c1 == (a + b), "Add2 IntPtr");
            Debug.Assert(c2 == (a + b), "Add3 IntPtr");

            return c2;
        }

        #endregion 整型与指针

        #region 数组

        /// <summary>
        /// 输入整型数组,int[]
        /// </summary>
        /// <param name="a"></param>
        /// <param name="len"></param>
        /// <param name="c"></param>
        [DllImport(_cppDll)]
        private static extern void Sum(int[] a, int len, ref int c);

        /// <summary>
        /// 输入整型数组 ,IntPtr
        /// </summary>
        /// <param name="a"></param>
        /// <param name="len"></param>
        /// <param name="c"></param>
        [DllImport(_cppDll)]
        private static extern void Sum(IntPtr a, int len, ref int c);

        /// <summary>
        /// 输入整型数组,int[]
        /// </summary>
        /// <param name="a"></param>
        /// <param name="len"></param>
        /// <param name="c"></param>
        [DllImport(_cppDll)]
        private static extern void Sum2(int[] a, int len, ref int c);

        /// <summary>
        /// 输入整型数组 ,IntPtr
        /// </summary>
        /// <param name="a"></param>
        /// <param name="len"></param>
        /// <param name="c"></param>
        [DllImport(_cppDll)]
        private static extern void Sum2(IntPtr a, int len, ref int c);

        public static int Sum(int[] ra)
        {
            //int[] ra = new int[] { 5, 4, 3, 2, 1 };

            int sum = 0;
            IntropCpp.Sum(ra, ra.Length, ref sum);
            Debug.Assert(sum == ra.ToList().Sum());

            sum = 0;
            IntPtr pas = Marshal.AllocCoTaskMem(sizeof(int) * ra.Length);
            Marshal.Copy(ra, 0, pas, ra.Length);
            IntropCpp.Sum(pas, ra.Length, ref sum);
            Marshal.FreeCoTaskMem(pas);
            Debug.Assert(sum == ra.ToList().Sum());

            sum = 0;
            IntropCpp.Sum2(ra, ra.Length, ref sum);
            Debug.Assert(sum == ra.ToList().Sum());

            //新建一个整型指针，分配数组长度的空间，将数组数据赋值到指针
            sum = 0;
            IntPtr pas2 = Marshal.AllocCoTaskMem(sizeof(int) * ra.Length);
            Marshal.Copy(ra, 0, pas2, ra.Length);
            IntropCpp.Sum2(pas2, ra.Length, ref sum);
            Marshal.FreeCoTaskMem(pas2);
            Debug.Assert(sum == ra.ToList().Sum());

            //获取数组对象在索引0元素的地址
            sum = 0;
            IntPtr pas22 = Marshal.UnsafeAddrOfPinnedArrayElement(ra, 0);
            IntropCpp.Sum2(pas22, ra.Length, ref sum);
            Debug.Assert(sum == ra.ToList().Sum());

            return sum;
        }

        /// <summary>
        /// C#申请非托管内存，C#释放非托管内存
        /// <br/>
        /// 函数需要调用两次，第一次，使用空指针获取需要需要申请的内存大小
        /// <br/>
        /// 第一次，使用空指针获取需要需要申请的内存大小
        /// <br/>
        /// 第二次，更据返回的内存大小，申请内存空间，然后使用分配空间的指针调用C++函数
        /// </summary>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <param name="range"></param>
        /// <param name="len"></param>
        [DllImport(_cppDll)]
        private static extern void Range(int start, int end, IntPtr range, ref int len);

        /// <summary>
        /// 输出数组不需要添加out ref修饰，否则C#函数返回后，出现内存访问异常
        /// </summary>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <param name="range"></param>
        /// <param name="len"></param>
        [DllImport(_cppDll)]
        private static extern void Range(int start, int end, int[] range, ref int len);

        public static void Range(int start, int end, out int[] range)
        {
            IntPtr ptr = IntPtr.Zero;
            int len = 0;
            Range(start, end, ptr, ref len);
            if (len <= 0)
            {
                range = null;
                return;
            }
            ptr = Marshal.AllocHGlobal(sizeof(int) * len);
            Range(start, end, ptr, ref len);
            int[] ret = new int[len];
            Marshal.Copy(ptr, ret, 0, len);
            range = ret;
            Marshal.FreeHGlobal(ptr);
            for (int i = start; i <= end; i++)
            {
                Debug.Assert(range[i - start] == i);
            }
            int[] ret2 = new int[end - start + 1];
            int len2 = 0;
            Range(start, end, ret2, ref len2);
            for (int i = start; i <= end; i++)
            {
                Debug.Assert(ret2[i - start] == i);
            }
        }

        /// <summary>
        /// 输入要排序的数组，输出排序后的数组
        /// </summary>
        /// <param name="input"></param>
        /// <param name="len"></param>
        /// <param name="output"></param>
        [DllImport(_cppDll)]
        private static extern void Sort(int[] input, int len, int[] output);

        /// <summary>
        /// 输入要排序的数组指针，输出排序后的数组指针
        /// </summary>
        /// <param name="input"></param>
        /// <param name="len"></param>
        /// <param name="output"></param>
        [DllImport(_cppDll)]
        private static extern void Sort(IntPtr input, int len, IntPtr output);

        public static void Sort(int[] input, out int[] output)
        {
            if (input == null)
                output = null;
            if (input.Length == 0)
                output = new int[0];
            output = new int[input.Length];
            Sort(input, input.Length, output);
            for (int i = 0; i < output.Length - 1; i++)
            {
                Debug.Assert(output[i] <= output[i + 1]);
            }

            Array.Clear(output, 0, output.Length);
            IntPtr pi = Marshal.AllocHGlobal(sizeof(int) * input.Length);
            IntPtr po = Marshal.AllocHGlobal(sizeof(int) * input.Length);
            Marshal.Copy(input, 0, pi, input.Length);
            Sort(pi, input.Length, po);
            Marshal.Copy(po, output, 0, output.Length);
            for (int i = 0; i < output.Length - 1; i++)
            {
                Debug.Assert(output[i] <= output[i + 1]);
            }
            Marshal.FreeHGlobal(pi);
            Marshal.FreeHGlobal(po);
        }

        #endregion 数组

        #region 字符串

        /// <summary>
        /// 输入字符串指针，输出字符串指针
        /// </summary>
        /// <param name="input"></param>
        /// <param name="strLen"></param>
        /// <param name="output"></param>
        [DllImport(_cppDll, CharSet = CharSet.Auto)]
        private static extern void Upper(IntPtr input, IntPtr output);

        /// <summary>
        /// 输入字符串指针，原地址修改字符串内容
        /// </summary>
        /// <param name="input"></param>
        /// <param name="strLen"></param>
        [DllImport(_cppDll, CharSet = CharSet.Auto)]
        private static extern void Lower(IntPtr input);

        [DllImport(_cppDll, CharSet = CharSet.Auto)]
        private static extern void Lower2(IntPtr input);

        [DllImport(_cppDll, CharSet = CharSet.Ansi)]
        private static extern void PrintfAnsi(IntPtr str, int len);

        [DllImport(_cppDll, CharSet = CharSet.Unicode)]
        private static extern void PrintfUni(IntPtr str, int len);

        [DllImport(_cppDll, CharSet = CharSet.Ansi)]
        public static extern void PrintfAnsiString(string str);

        /// <summary>
        /// 需要两次调用，第一次仅获取字符串大小，申请空间后再次调用
        /// </summary>
        /// <param name="errorCode"></param>
        /// <param name="info"></param>
        /// <param name="len"></param>
        [DllImport(_cppDll, EntryPoint = "GetErrorInfoEx", CharSet = CharSet.Ansi)]
        public static extern void GetErrorInfo(int errorCode, IntPtr info, IntPtr len);

        public static void OutputString()
        {
            var ecodes = new List<int>()
            {
                0,2,2022
            };
            foreach (var e in ecodes)
            {
                IntPtr el = Marshal.AllocHGlobal(sizeof(int));
                GetErrorInfo(e, IntPtr.Zero, el);
                var strlen = Marshal.ReadInt32(el);
                //仅返回字符串长度不含结束符，因此此处需要多申请一个字符的空间用于存储结束字符
                var pstr = Marshal.AllocHGlobal(sizeof(char) * (strlen + 1));
                GetErrorInfo(e, pstr, el);
                var info = Marshal.PtrToStringAnsi(pstr);

                Marshal.FreeHGlobal(el);
                Marshal.FreeHGlobal(pstr);
                Console.WriteLine("错误码:{0} \t描述:{1}", e, info);
            }
        }

        public static void UpperLower(string input, out string upstr, out string lwstr)
        {
            upstr = null;
            lwstr = null;
            if (input == null)
                return;
            var pinput = Marshal.StringToHGlobalAnsi(input);
            var len = input.Length;
            upstr = string.Copy(input);
            lwstr = string.Copy(input);
            var lwstr2 = string.Copy(input);
            var pustr = Marshal.StringToHGlobalAnsi(upstr);
            var plstr1 = Marshal.StringToHGlobalAnsi(lwstr);
            var plstr2 = Marshal.StringToHGlobalAnsi(lwstr2);

            Upper(pinput, pustr);
            Lower(plstr1);
            Lower2(plstr2);

            upstr = Marshal.PtrToStringAnsi(pustr);
            lwstr = Marshal.PtrToStringAnsi(plstr1);
            lwstr2 = Marshal.PtrToStringAnsi(plstr2);

            Marshal.FreeHGlobal(pustr);
            Marshal.FreeHGlobal(plstr1);
            Marshal.FreeHGlobal(plstr2);

            Debug.Assert(upstr == input.ToUpper());
            Debug.Assert(lwstr == input.ToLower());
            Debug.Assert(lwstr2 == input.ToLower());
        }

        public static void Printf(string str)
        {
            Console.WriteLine("传递：" + str);
            var pinput = Marshal.StringToHGlobalAnsi(str);
            //C#的字符串长度与C/C++的字符串长度在对待中文时计算不同
            PrintfAnsiString(str);
            PrintfAnsi(pinput, str.Length);
            Marshal.FreeHGlobal(pinput);
        }

        #endregion 字符串

        #region 类操作

        [DllImport(_cppDll)]
        public static extern int CreatePoint(IntPtr ptr, float x, float y);

        [DllImport(_cppDll)]
        public static extern int DeletePoint(IntPtr ptr);

        [DllImport(_cppDll)]
        public static extern int DeletePoint2(IntPtr ptr);

        [DllImport(_cppDll)]
        public static extern float Distance(IntPtr ptr);

        [DllImport(_cppDll)]
        public static extern float Distance2(IntPtr ptr1, IntPtr ptr2);

        #endregion 类操作

        #region 结构体操作

        [DllImport(_cppDll)]
        public static extern int Input(int flag, IntPtr ptr, int count);

        public static int InputEx<TStruct>(int flag, TStruct data, int count)
            where TStruct : struct
        {
            var size = Marshal.SizeOf(data);
            var ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(data, ptr, true);
            var r = IntropCpp.Input(flag, ptr, 1);
            Marshal.DestroyStructure(ptr, typeof(IpInfo));
            return r;
        }
        #endregion
    }

    public static class IntrophdCodeTest
    {
        public class KeyValueList<TKey, TValue> : List<KeyValuePair<TKey, TValue>>
        {
            public void Add(TKey key, TValue value)
            {
                Add(new KeyValuePair<TKey, TValue>(key, value));
            }
        }

        #region 无分支指令计算

        private static int doz(int x, int y)
        {
            return x > y ? x - y : 0;
        }

        private static int min(int x, int y)
        {
            return x > y ? y : x;
        }

        private static int max(int x, int y)
        {
            return x > y ? x : y;
        }

        private static uint doz(uint x, uint y)
        {
            return x > y ? x - y : 0;
        }

        private static int sign(int x)
        {
            if (x > 0)
                return 1;
            else if (x < 0)
                return -1;
            else
                return 0;
        }

        private static int cmp(int x, int y)
        {
            if (x < y)
                return -1;
            if (x > y)
                return 1;
            return 0;
        }

        private static int isign(int x, int y)
        {
            if (y >= 0)
                return abs(x);
            if (y < 0)
                return -abs(x);
            return x;
        }

        private static int abs(int x)
        {
            return Math.Abs(x);
        }

        private static int nabs(int x)
        {
            return -abs(x);
        }

        private static void swap(ref int x, ref int y)
        {
            int t = x;
            x = y;
            y = t;
        }

        #endregion 无分支指令计算

        #region 舍入问题

        private static int flp(int x, int ds)
        {
            if (x < 0)
                return x;
            if (x == 0)
                return 0;
            int k = (int)Math.Log(ds, 2);
            int val = (int)Math.Pow(2, k);
            if (x % val == 0)
                return x;
            x--;
            return flp(x, ds);
        }

        private static int clp(int x, int ds)
        {
            if (x < 0)
                return x;
            if (x == 0)
                return 0;
            int k = (int)Math.Log(ds, 2);
            int val = (int)Math.Pow(2, k);
            if (x % val == 0)
                return x;
            x++;
            if (x == int.MaxValue)
                return -1;
            return clp(x, ds);
        }

        #endregion 舍入问题

        public static void RunTest()
        {
            var vals0 = new List<int>()
            {
                0,-11,33,int.MaxValue
            };

            var vals1 = new List<int>()
            {
                0,-11,33,int.MaxValue,int.MinValue
            };

            var vals2 = new KeyValueList<int, int>()
            {
                { 0,0},{ 0,10},{ 0,-10},{ -10,0},{ 10,0},
                { 12,13},{ 13,12},{ -12,13},{ -13,12},{ 12,-13},{ 13,-12},{ -12,-13},{ -13,-12},
                { int.MinValue,int.MinValue},
                { int.MaxValue,int.MaxValue},
                { int.MinValue,int.MaxValue},
                { int.MaxValue,int.MinValue},
                { 0,int.MinValue},{ 0,int.MaxValue},{ -10,int.MinValue},{ -10,int.MaxValue},
                { 10,int.MinValue},{ 10,int.MaxValue},
            };

            var vals3 = new KeyValueList<int, int>()
            {
                { 0,0},{ 0,10},{ 0,-10},{ -10,0},{ 10,0},
                { 12,13},{ 13,12},{ -12,13},{ -13,12},{ 12,-13},{ 13,-12},{ -12,-13},{ -13,-12},
                { int.MaxValue,int.MaxValue},
                { 0,int.MaxValue},{ -10,int.MaxValue},
            };

            vals2.ToList().ForEach(tv => Debug.Assert(IntrophdCode.doz(tv.Key, tv.Value) == doz(tv.Key, tv.Value)));
            vals2.ToList().ForEach(tv => Debug.Assert(IntrophdCode.min(tv.Key, tv.Value) == min(tv.Key, tv.Value)));
            vals2.ToList().ForEach(tv => Debug.Assert(IntrophdCode.max(tv.Key, tv.Value) == max(tv.Key, tv.Value)));

            vals0.ForEach(v => Debug.Assert(IntrophdCode.abs(v) == abs(v)));
            vals0.ForEach(v => Debug.Assert(IntrophdCode.nabs(v) == nabs(v)));
            vals1.ForEach(v => Debug.Assert(IntrophdCode.sign(v) == sign(v)));

            vals2.ToList().ForEach(tv => Debug.Assert(IntrophdCode.cmp(tv.Key, tv.Value) == cmp(tv.Key, tv.Value)));
            vals3.ToList().ForEach(tv => Debug.Assert(IntrophdCode.isign(tv.Key, tv.Value) == isign(tv.Key, tv.Value)));

            int x = 11, y = 22;
            var x0 = x;
            var y0 = y;
            swap(ref x, ref y);
            IntrophdCode.swap(ref x, ref y);
            Debug.Assert(x0 == x);
            Debug.Assert(y0 == y);

            var ls = new List<int>() { 9, 16, 65, 79 };
            var r0 = ls.Select(v =>
            {
                var t0 = flp(v, 8);
                var t1 = IntrophdCode.flp(v, 8);
                return Tuple.Create(t0 == t1, t0, t1);
            });
            var r1 = ls.Select(v =>
            {
                var t0 = clp(v, 8);
                var t1 = IntrophdCode.clp(v, 8);
                return Tuple.Create(t0 == t1, t0, t1);
            });

            Debug.Assert(r0.All(t => t.Item1));
            Debug.Assert(r1.All(t => t.Item1));
        }
    }

    public static class IntrophdCode
    {
        private const string _cppDll = "cpp.dll";

        #region 无分支指令

        /// <summary>
        /// 无分支指令 差或0函数
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        [DllImport(_cppDll)]
        public static extern int doz(int a, int b);

        /// <summary>
        /// 无分支指令 差或0函数
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        [DllImport(_cppDll)]
        public static extern uint dozu(uint a, uint b);

        [DllImport(_cppDll, EntryPoint = "_max")]
        public static extern int max(int a, int b);

        [DllImport(_cppDll, EntryPoint = "_min")]
        public static extern int min(int a, int b);

        [DllImport(_cppDll, EntryPoint = "_maxu")]
        public static extern int maxu(int a, int b);

        [DllImport(_cppDll, EntryPoint = "_minu")]
        public static extern int minu(int a, int b);

        /// <summary>
        /// 绝对值函数
        /// </summary>
        /// <param name="a"></param>
        /// <returns></returns>
        [DllImport(_cppDll, EntryPoint = "_abs")]
        public static extern int abs(int a);

        /// <summary>
        /// 负绝对值函数
        /// </summary>
        /// <param name="a"></param>
        /// <returns></returns>
        [DllImport(_cppDll, EntryPoint = "_nabs")]
        public static extern int nabs(int a);

        /// <summary>
        /// 符号函数
        /// </summary>
        /// <param name="a"></param>
        /// <returns></returns>
        [DllImport(_cppDll, EntryPoint = "sign")]
        public static extern int sign(int x);

        /// <summary>
        /// 三值比较函数
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        [DllImport(_cppDll, EntryPoint = "cmp")]
        public static extern int cmp(int x, int y);

        /// <summary>
        /// 符号传递函数
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        [DllImport(_cppDll, EntryPoint = "isign")]
        public static extern int isign(int x, int y);

        [DllImport(_cppDll, EntryPoint = "swap")]
        public static extern void swap(ref int x, ref int y);

        #endregion 无分支指令

        #region 舍入问题

        [DllImport(_cppDll, EntryPoint = "flp")]
        public static extern int flp(int x, int ds);

        [DllImport(_cppDll, EntryPoint = "clp")]
        public static extern int clp(int x, int ds);

        #endregion 舍入问题
    }
}